package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.config.redisson.RedissonConfig;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.micrometer.core.instrument.util.TimeUtils;
import jodd.time.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private AlbumAttributeValueService albumAttributeValueService;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
		/*
		album_attribute_value
		album_info
		album_stat
		 */
        try {
            //1.先保存专辑信息表  album_info
            AlbumInfo albumInfo = new AlbumInfo();
            //属性赋值：前提条件是属性名必须一致！
            BeanUtils.copyProperties(albumInfoVo, albumInfo);
            //前端保存的数据是否都要保存到数据表或保存数据表中的数据，前端都传递了吗？校验
            //需要知道当前专辑是谁创建的？userid；获取当前登录用户id；tracks_for_free（付费专辑的时候，需要先让用户进行试听）
            albumInfo.setUserId(userId);
            //设置试听集数
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfoVo.getPayType())) {
                //付费试听集数
                albumInfo.setTracksForFree(5);
            }
            //设置审核状态，发送一个消息，给管理平台站内信（提示信息）审核通过监听消息完成审核状态赋值
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
            //执行insert方法
            albumInfoMapper.insert(albumInfo);
            //2.保存标签  album_attribute_value
            List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
            if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
    /*            //循环遍历赋值
                for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                    //创建对象
                    AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                    //赋值
                    albumAttributeValue.setAlbumId(albumInfo.getId());
                    albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                    albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                    //执行多次insert into
                    albumAttributeValueMapper.insert(albumAttributeValue);
                }*/
                List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList.stream().map(albumAttributeValueVo -> {
                    AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                    BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                    albumAttributeValue.setAlbumId(albumInfo.getId());
                    return albumAttributeValue;
                }).collect(Collectors.toList());
                // 批量保存
                this.albumAttributeValueService.saveBatch(albumAttributeValueList);
            }
            //album_stat
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
            saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);

            //如果当前专辑是公开；is_open=1
            if ("1".equals(albumInfo.getIsOpen())) {
                //调用上架方法
                rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
                //将专辑id添加到布隆过滤器中
                RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
                bloomFilter.add(albumInfo.getId());
            }
        } catch (BeansException e) {
            //  开发中都需要使用这种方式进行日志输出，不能直接使用e.printStackTrace(); 会占用资源！
            log.error(e.getMessage(), e);
            throw new GuiguException(ResultCodeEnum.SERVICE_ERROR);
            //不可达代码
            //return false;
        }

        return true;
    }

    public void saveAlbumStat(Long albumId, String statPlay) {
        //创建对象
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatNum(new Random().nextInt(100000));
        albumStat.setStatType(statPlay);
        albumStatMapper.insert(albumStat);
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> page, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.selectUserAlbumPage(page, albumInfoQuery);
    }

    @Override
    @TsCache(keyPrefix = "album:")//useLock = true
    public AlbumInfo getAlbumInfo(Long albumId) {
       /* // 定义string类型
        String dataKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
        AlbumInfo albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
        try {
            //判断缓存中是否有数据
            if (null == albumInfo) {
                System.out.println("缓存无数据");
                //不存在，查询数据库
                //加锁
                String lockKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
                RLock lock = redissonClient.getLock("lockKey");
                lock.lock();
                try {
                    //查询数据库前再判断一次缓存
                    albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
                    if (null != albumInfo) {
                        return albumInfo;
                    }
                    //业务查询
                    albumInfo = getAlbumInfoDB(albumId);
                    if (null == albumInfo) {
                        //防止穿透,设置空值
                        this.redisTemplate.opsForValue().set(dataKey, new AlbumInfo(), RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        return new AlbumInfo();
                    }
                    //数据库有数据
                    this.redisTemplate.opsForValue().set(dataKey, albumInfo, RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS);
                    //返回数据
                    return albumInfo;
                } catch (Exception e) {
                    // 异常信息
                    log.error(e.getMessage(), e);
                } finally {
                    //解锁
                    lock.unlock();
                }
            } else {
                System.out.println("缓存有数据");
                return albumInfo;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }*/
        //数据库兜底
        return getAlbumInfoDB(albumId);
    }

    private @Nullable AlbumInfo getAlbumInfoDB(Long albumId) {
        //  因为需要给专辑标签赋值; albumAttributeValueVoList
        //  查询专辑信息表;
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //  为了防止空指针
        if (null != albumInfo) {
            //  根据专辑Id获取到标签数据：
            //  select * from album_attribute_value where album_id = 1630 ;
            //  Warpper 构建查询条件的;
            LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AlbumAttributeValue::getAlbumId, albumId);
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(wrapper);
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        }
        //  返回数据
        return albumInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //  update album_info set title = ? where id = ?;
        AlbumInfo albumInfo = new AlbumInfo();
        //  属性拷贝：
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        albumInfo.setId(albumId);
        albumInfoMapper.updateById(albumInfo);
        //  album_attribute_value 由于修改值的时候未触发控制器，所以不能实时记录修改的信息。因此要先删除数据，再新增数据！
        //  删除原有标签数据; delete from album_attribute_value where album_id = ?; 物理删除; 因为实体类中有一个isDelete字段 TableLgoic 逻辑删除！
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            //  循环遍历修改数据
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //  创建修改的实体对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //  属性拷贝;
                BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
                albumAttributeValue.setAlbumId(albumId);

                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }

        //判断当前专辑是公开,is_open=1
        if ("1".equals(albumInfo.getIsOpen())) {
            //调用上架方法
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            //将专辑id添加到布隆过滤器中
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            bloomFilter.add(albumId);
        } else {
            //调用下架方法
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long albumId) {
        //album_info  album_attribute_value  album_stat
        //删除 album_info
        albumInfoMapper.deleteById(albumId);
        //删除 album_attribute_value
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId));
        //删除 album_stat
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId, albumId));
        //删除声音？ 主要看产品需求
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        //构建查询条件
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlbumInfo::getUserId, userId);
        wrapper.orderByDesc(AlbumInfo::getId);
        Page<AlbumInfo> page = new Page<>(1, 100);
        IPage<AlbumInfo> infoIPage = albumInfoMapper.selectPage(page, wrapper);
        return infoIPage.getRecords();
    }

    @Override
    @TsCache(keyPrefix = "statVo:")//useLock = true
    public AlbumStatVo getAlbumStat(Long albumId) {
        return albumInfoMapper.selectAlbumStat(albumId);
    }
}
